"use strict";

const crypto = require("crypto");
const axios = require("axios");
const env = require("../config");
const jwt = require("jsonwebtoken");
const _ = require("lodash");
const { DingReturnCode: ReturnCode } = require("./../utils/KEnum");
const KError = require("./../utils/KError");

let EXPIRES = 0;
let EXPIRES_TOKEN = 0;
let TICKET = "";
let ACCESS_TOKEN = "";
const OAPIHOST = "https://oapi.dingtalk.com";

/**
 * 获取签名
 * @param {String} url
 * @param {String} nonceStr
 * @param {String} timeStamp
 */
async function getSign(url, nonceStr, timeStamp) {
  const ticket = await getJsapiTicket();
  const plain = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timeStamp}&url=${url}`;
  const sha1 = crypto.createHash("sha1");
  sha1.update(plain, "utf8");
  const signature = sha1.digest("hex");
  return signature;
}

/**
 * 获取jsTicket
 */
async function getJsapiTicket() {
  const accessToken = await getAccessToken();
  if (!EXPIRES || EXPIRES < Date.now() + 20 * 60 * 1000) {
    //ticket 超时，重新获取
    const { data } = await axios.get(
      `${OAPIHOST}/get_jsapi_ticket?access_token=${accessToken}`
    );
    const { errcode, ticket } = data;
    if (errcode === ReturnCode.SUCCESS) {
      TICKET = ticket;
      EXPIRES = Date.now() + 7200 * 1000;
      return TICKET;
    }
  } else {
    return TICKET;
  }
}

/**
 * 获取accessToken
 */
async function getAccessToken() {
  if (!EXPIRES_TOKEN || EXPIRES_TOKEN < Date.now() + 20 * 60 * 100) {
    //提前20分钟获取 access_token
    const { data } = await axios.get(
      `${OAPIHOST}/gettoken?appkey=${env.APP_KEY}&appsecret=${env.APP_SECRET}`
    );
    const { errcode, access_token } = data;
    if (errcode === ReturnCode.SUCCESS) {
      ACCESS_TOKEN = access_token;
      EXPIRES_TOKEN = Date.now() + 7200 * 1000;
      return access_token;
    }
  } else {
    return ACCESS_TOKEN;
  }
}

/**
 * 根据userId 获取用户详情
 * @param {String} userId
 */
exports.getUserInfoById = async (userId) => {
  if (_.isNil(userId))
    throw KError.InvalidFormatData("func getUserInfoById => userId is Nil");
  const accessToken = await getAccessToken();
  const { data } = await axios.get(
    `${OAPIHOST}/user/get?access_token=${accessToken}&userid=${userId}`
  );
  const { errcode, errmsg } = data;
  if (errcode === ReturnCode.SUCCESS) return data;
  else throw KError.DingError(errmsg);
};

/**
 * 获取钉钉JSAPI鉴权 config
 */
exports.getDingConfig = async () => {
  const { DOMAIN: url, AGENTID: agentId, CORP_ID: corpId } = env;
  const timeStamp = Date.now();
  const nonceStr = "coco" + (Math.random() * 1000).toFixed(0); //签名随机数
  const signature = await getSign(url, nonceStr, timeStamp);
  return {
    agentId, // 必填，微应用ID
    corpId, //必填，企业ID
    timeStamp, // 必填，生成签名的时间戳
    nonceStr, // 必填，生成签名的随机串
    signature, // 必填，签名
    type: 0, //选填。0表示微应用的jsapi,1表示服务窗的jsapi。不填默认为0。该参数从dingtalk.js的0.8.3版本开始支持
  };
};

/**
 * 免登 获取用户详情
 * @param {String} code 免登授权码
 */
exports.OAuthLogin = async (code) => {
  if (_.isNil(code)) throw "func OAuthLogin => code is Nil";
  const accessToken = await getAccessToken();
  const { data } = await axios.get(
    `${OAPIHOST}/user/getuserinfo?access_token=${accessToken}&code=${code}`
  );
  const { errcode, errmsg } = data;
  if (errcode === ReturnCode.SUCCESS) {
    const { name, userid, is_sys, sys_level, deviceId } = data;
    const token = jwt.sign(
      {
        name,
        userId: userid,
        is_sys,
        sys_level,
        deviceId,
      },
      env.SECRET_KEY
    );
    return {
      token,
      user: data,
    };
  } else throw KError.DingError(errmsg);
};

/**
 * 获取部门列表
 */
exports.getDeptList = async () => {
  const accessToken = await getAccessToken();
  const { data } = await axios.get(
    `${OAPIHOST}/department/list?access_token=${accessToken}`
  );
  const { errcode, errmsg, department } = data;
  if (errcode === ReturnCode.SUCCESS) return department;
  else throw KError.DingError(errmsg);
};

/**
 * 获取部门详情
 */
exports.getDeptInfo = async (id) => {
  const accessToken = await getAccessToken();
  const { data } = await axios.get(
    `${OAPIHOST}/department/get?access_token=${accessToken}&id=${id}`
  );
  const { errcode, errmsg } = data;
  if (errcode === ReturnCode.SUCCESS) return data;
  else throw KError.DingError(errmsg);
};
